package net.kosev.battleships;

import net.kosev.battleships.adapters.EnemyBoardAdapter;
import net.kosev.battleships.adapters.PlayerBoardAdapter;
import net.kosev.battleships.model.BattleshipsException;
import net.kosev.battleships.model.Board;
import net.kosev.battleships.model.Game;
import net.kosev.battleships.model.GameListener;
import net.kosev.battleships.model.ai.EasyEnemyAI;
import net.kosev.battleships.model.ai.EnemyAI;
import net.kosev.battleships.model.ai.NormalEnemyAi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Game Activity
 * 
 * @author Nikola
 *
 */
public class GameScreen extends Activity implements GameListener {
	
	/**
	 * Big grid component
	 */
	private GridView mEnemyGrid = null;
	
	/**
	 * Small grid component
	 */
	private GridView mPlayerGrid = null;
	
	/**
	 * Big grid adapter
	 */
	private EnemyBoardAdapter mEnemyAdapter = null;
	
	/**
	 * Small grid adapter
	 */
	private PlayerBoardAdapter mPlayerAdapter = null;
	
	/**
	 * Crosshair instance
	 */
	private ImageView mCrosshair = null;
	
	/**
	 * Player score label component
	 */
	private TextView mLabelPlayer = null;
	
	/**
	 * Enemy score label component
	 */
	private TextView mLabelEnemy = null;
	
	/**
	 * Menu button component
	 */
	private Button mMenu = null;
	
	/**
	 * Enemy AI instance
	 */
	private EnemyAI mAi = null;
	
	/**
	 * Game sound instance
	 */
	private Sound mSound = null;
	
	/**
	 * Game instance
	 */
	public static Game mGame = null;
	
	/**
	 * True if crosshair is moving
	 */
	private boolean capturedCrosshair = false;
	
	/**
	 * Is crosshair moved
	 */
	private boolean movedCrosshair = false;
	
	/**
	 * Drag starting X position
	 */
	private int capturedX;
	
	/**
	 * Drag starting Y position
	 */
	private int capturedY;
	
	/**
	 * X distance from crosshair corner to drag position
	 */
	private int innerX;
	
	/**
	 * Y distance from crosshair corner to drag position
	 */
	private int innerY;
	
	/**
	 * Selected column on enemy's grid
	 */
	private int selectedRow = -1;
	
	/**
	 * Selected row on enemy's grid
	 */
	private int selectedCol = -1;

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Intent intent = new Intent(this, ArrangeScreen.class);
		startActivityForResult(intent, 0);
	}
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		
		if (resultCode == ArrangeScreen.RESULT_CANCEL) {
			finish();
		} else {
			initScreen();
		}
	}

	/**
	 * Initialize activity objects
	 */
	private void initScreen() {
		setContentView(R.layout.game);
		
		mGame.getPlayerBoard().setRuleRevealing(Config.enabledRevealing);
		mGame.getEnemyBoard().setRuleRevealing(Config.enabledRevealing);
		mGame.setGameListener(this);
		
		mAi = createAi();
		mAi.setBoard(mGame.getPlayerBoard());
		
		mEnemyGrid = (GridView) findViewById(R.id.EnemyGrid);
		mEnemyAdapter = new EnemyBoardAdapter(this, mGame.getEnemyBoard().getFields());
		mEnemyGrid.setAdapter(mEnemyAdapter);
		
		mPlayerGrid = (GridView) findViewById(R.id.PlayerGrid);
		mPlayerAdapter = new PlayerBoardAdapter(this, mGame.getPlayerBoard().getFields());
		mPlayerGrid.setAdapter(mPlayerAdapter);
		
		mCrosshair = (ImageView) findViewById(R.id.Crosshair);
		
		mLabelPlayer = (TextView) findViewById(R.id.LabelPlayer);
		mLabelEnemy = (TextView) findViewById(R.id.LabelEnemy);
		
		mMenu = (Button) findViewById(R.id.ButtonMenu);
		mMenu.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				showDialog(DIALOG_GAMEMENU_ID);
			}
		});
		
		mSound = new Sound(this);
		
		setVolumeControlStream(AudioManager.STREAM_MUSIC);
		
		initConstants();
	}
	
	/**
	 * Initialize DPI-dependent constants
	 */
	private void initConstants() {
		cellSize = Math.round(Utils.conv(this, 30));
		crossCenterX = Math.round(Utils.conv(this, 55));
		crossCenterY = Math.round(Utils.conv(this, 53));
		crossPadding = Math.round(Utils.conv(this, 25));
		crossPaddingBottom = Math.round(Utils.conv(this, 85));
		crossSelectorTop = Math.round(Utils.conv(this, 0)); // old is 90
		crossSelectorBottom = Math.round(Utils.conv(this, 15));
		crossSelectorLeft = Math.round(Utils.conv(this, 15));
		crossSelectorRight = Math.round(Utils.conv(this, 15));
		toleranceLeft = Math.round(Utils.conv(this, 50));
		toleranceRight = Math.round(Utils.conv(this, 50));
		toleranceTop = Math.round(Utils.conv(this, 48));
		toleranceBottom = Math.round(Utils.conv(this, 60));
		moveRadius = Math.round(Utils.conv(this, 14));
	}
	
	/**
	 * Cell size; width == height
	 */
	private int cellSize;
	
	/**
	 * Distance from left border to spot on the crosshair
	 */
	private int crossCenterX;
	
	/**
	 * Distance from top border to spot on the crosshair
	 */
	private int crossCenterY;
	
	/**
	 * Fire bounding box padding
	 */
	private int crossPadding;
	
	/**
	 * Fire bounding box bottom padding
	 */
	private int crossPaddingBottom;
	
	/**
	 * Distance from top border to starting area of crosshair selector
	 */
	private int crossSelectorTop;
	
	/**
	 * Distance from bottom border to starting area of crosshair selector
	 */
	private int crossSelectorBottom;
	
	/**
	 * Distance from left border to starting area of crosshair selector
	 */
	private int crossSelectorLeft;
	
	/**
	 * Distance from right border to starting area of crosshair selector
	 */
	private int crossSelectorRight;
	
	/**
	 * Distance crosshair can go left
	 */
	private int toleranceLeft;
	
	/**
	 * Distance crosshair can go right
	 */
	private int toleranceRight;
	
	/**
	 * Distance crosshair can go top
	 */
	private int toleranceTop;
	
	/**
	 * Distance crosshair can go bottom
	 */
	private int toleranceBottom;
	
	/**
	 * Radius crosshair can be moved to allow fire
	 */
	private int moveRadius;

	/* (non-Javadoc)
	 * @see android.app.Activity#dispatchTouchEvent(android.view.MotionEvent)
	 */
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		boolean result = true;
		
		final int action = event.getAction();
		
		final int x = (int) event.getX();
		final int y = (int) event.getY();
		
		FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mCrosshair.getLayoutParams();
		final int crossWidth = params.width;
		final int crossHeight = params.height;
		final int crossMinX = params.leftMargin;
		final int crossMaxX = params.leftMargin + crossWidth;
		final int crossMinY = params.topMargin;
		final int crossMaxY = params.topMargin + crossHeight;
		
		
		int[] location = new int[2];
		mEnemyGrid.getLocationOnScreen(location);
		final int gridWidth = mEnemyGrid.getWidth();
		final int gridHeight = mEnemyGrid.getHeight();
		final int gridMinX = location[0];
		final int gridMaxX = location[0] + gridWidth;
		final int gridMinY = location[1];
		final int gridMaxY = location[1] + gridHeight;
		location = null;

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			if (x >= crossMinX - crossSelectorLeft && x <= crossMaxX + crossSelectorRight && y >= crossMinY + crossSelectorTop && y <= crossMaxY + crossSelectorBottom) {
				
				capturedCrosshair = true;
				innerX = x - crossMinX;
				innerY = y - crossMinY;
				capturedX = x;
				capturedY = y;
				
				if (x >= crossMinX + crossPadding && x <= crossMaxX - crossPadding && y >= crossMinY + crossPadding && y <= crossMinY + crossPaddingBottom) {
					// if tap is near crosshair center, allow fire
					movedCrosshair = false;
				} else {
					movedCrosshair = true;
				}
				
			} else {
				result = false;
			}
			break;
			
		case MotionEvent.ACTION_MOVE:
			if (capturedCrosshair) {
				final int tempX = x - innerX;
				final int tempY = y - innerY;
				
				if (tempX >= gridMinX - toleranceLeft && tempX <= gridMaxX - crossWidth + toleranceRight) {
					params.leftMargin = tempX;
				} else {
					if (tempX < gridMinX - toleranceLeft) {
						params.leftMargin = gridMinX - toleranceLeft;
					} else if (tempX > gridMaxX - crossWidth + toleranceRight) {
						params.leftMargin = gridMaxX - crossWidth + toleranceRight;
					}
				}

				if (tempY >= gridMinY - toleranceTop && tempY <= gridMaxY - toleranceBottom) {
					params.topMargin = tempY;
				} else {
					if (tempY < gridMinY - toleranceTop) {
						params.topMargin = gridMinY - toleranceTop;
					} else if (tempY > gridMaxY - toleranceBottom) {
						params.topMargin = gridMaxY - toleranceBottom;
					}
				}
				
				if (Math.abs(x - capturedX) > moveRadius || Math.abs(y - capturedY) > moveRadius) {
					movedCrosshair = true;
				}
				
				mCrosshair.setLayoutParams(params);
				
			} else {
				result = false;
			}
			break;
			
		case MotionEvent.ACTION_UP:
			if (capturedCrosshair) {
				
				if (movedCrosshair == false && selectedCol != -1 && selectedRow != -1) { // fire !
					
					try {
						mGame.playerFires(selectedRow, selectedCol);
					} catch (BattleshipsException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				} 
					
				capturedCrosshair = false;
				
				selectedCol = (crossMinX - gridMinX + crossCenterX) / cellSize;
				selectedRow = (crossMinY - gridMinY + crossCenterY) / cellSize;
				
				final int cellCenterX = (selectedCol * cellSize) + (cellSize / 2);
				final int cellCenterY = (selectedRow * cellSize) + (cellSize / 2);
				
				params.leftMargin = gridMinX + cellCenterX - crossCenterX;
				params.topMargin = gridMinY + cellCenterY - crossCenterY;
				
				mCrosshair.setLayoutParams(params);
					
				
			} else {
				result = false;
			}
			break;
		}
		
		if (result == true) {
			return true;
		} else {
			return super.dispatchTouchEvent(event);
		}
	}
	
	/**
	 * Update score labels
	 */
	private void updateLabels() {
		mLabelPlayer.setText(mGame.getPlayerBoard().getRemainingLives() + " / " + mGame.getPlayerBoard().getTotalLives());
		mLabelEnemy.setText(mGame.getEnemyBoard().getRemainingLives() + " / " + mGame.getEnemyBoard().getTotalLives());
	}
	
	/**
	 * Id of the menu dialog
	 */
	public static final int DIALOG_GAMEMENU_ID = 0;
	
	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onCreateDialog(int)
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog;
	    switch(id) {
	    case DIALOG_GAMEMENU_ID:
	    	final CharSequence[] items = { getString(R.string.game_leave), getString(R.string.game_resume) };

	    	AlertDialog.Builder builder = new AlertDialog.Builder(this);
	    	builder.setTitle(getString(R.string.game_menu));
	    	builder.setItems(items, new DialogInterface.OnClickListener() {
	    	    public void onClick(DialogInterface dialog, int item) {
	    	        switch (item) {
	    	        case 0:
	    	        	finish();
	    	        	break;
	    	        case 1:
	    	        default:
	    	        	dismissDialog(DIALOG_GAMEMENU_ID);
	    	        }
	    	    }
	    	});
	    	dialog = builder.create();
	    	
	        break;
	    default:
	        dialog = null;
	    }
	    return dialog;
	}

	/* (non-Javadoc)
	 * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
	        showDialog(DIALOG_GAMEMENU_ID);
	        return true;
	    }
		return super.onKeyDown(keyCode, event);
	}

	public void playerFired(Game game, boolean success) {
		if (success) {
			mSound.playHit();
		} else {
			mSound.playMiss();
		}
		
		mEnemyAdapter.notifyDataSetChanged();
		updateLabels();
		
		int pos = mAi.getFirePosition();
		try {
			mGame.enemyFires(pos / Board.SIZE, pos % Board.SIZE);
		} catch (BattleshipsException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void enemyFired(Game game, boolean success) {
		mPlayerAdapter.notifyDataSetChanged();
		updateLabels();
	}

	public void gameEnded(Game game) {
		Intent intent = new Intent(this, ResultScreen.class);
		startActivityForResult(intent, 0);
	}
	
	/**
	 * Create AI instance
	 * 
	 * @return	AI instance
	 */
	private EnemyAI createAi() {
		EnemyAI result = null;
		
		switch (Config.computerDifficulty) {
		case 0: result = new EasyEnemyAI(); break;
		case 1:
		default: result = new NormalEnemyAi(); break;
		}
		
		return result;
	}
	
}
